package com.sky.aspect;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.sky.annotation.AutoFill;
import com.sky.context.BaseContext;
import com.sky.entity.Category;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

import static com.sky.constant.AutoFillConstant.*;

@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    /**
     * 定义切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {
    }

    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {
        //获取目标参数
        Object[] args = joinPoint.getArgs();
        //如果参数为null拒绝处理
        if (ArrayUtil.isEmpty(args)) {
            return;
        }
        //获取目标方法的第一个参数
        Object firstArg = args[0];
        //获取目标方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //获取注解
        AutoFill autoFill = method.getAnnotation(AutoFill.class);
        //获取注解的值
        OperationType value = autoFill.value();
        //系统此刻世间
        LocalDateTime localDateTime = LocalDateTime.now();
        //获取操作id
        Long currentId = BaseContext.getCurrentId();
        if (value == OperationType.INSERT) {
            try {
                Method createTime = firstArg.getClass().getDeclaredMethod(SET_CREATE_TIME, LocalDateTime.class);
                Method updateTime = firstArg.getClass().getDeclaredMethod(SET_UPDATE_TIME, LocalDateTime.class);
                Method createUser = firstArg.getClass().getDeclaredMethod(SET_CREATE_USER, Long.class);
                Method updateUser = firstArg.getClass().getDeclaredMethod(SET_UPDATE_USER, Long.class);
                //调用方法
                createTime.invoke(firstArg, localDateTime);
                updateTime.invoke(firstArg, localDateTime);
                createUser.invoke(firstArg, currentId);
                updateUser.invoke(firstArg, currentId);
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                log.error("自动填充失败");
            }

        } else {
            //更新操作
            try {
                Method updateTime = firstArg.getClass().getDeclaredMethod(SET_UPDATE_TIME, LocalDateTime.class);
                Method updateUser = firstArg.getClass().getDeclaredMethod(SET_UPDATE_USER, Long.class);
                //调用方法
                updateTime.invoke(firstArg, localDateTime);
                updateUser.invoke(firstArg, currentId);

            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                log.error("自动填充失败");
            }
            log.info("自动填充成功");

        }
    }

    /**
     * 定义前置通知
     *
     * @param joinPoint
     */
//    @Before("autoFillPointCut()")
    public void autoFillTest(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException {
        //获取当前id
        Long currentId = BaseContext.getCurrentId();
        //获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取目标方法
        Method method = signature.getMethod();
        //获取注解
        AutoFill annotation = method.getAnnotation(AutoFill.class);
        //获取操作名词
        OperationType value = annotation.value();
        //获取第一个参数
        Object firstArg = joinPoint.getArgs()[0];
        if (firstArg == null) {
            return;
        }
        //获取第一个参数的类
        Class<?> firstArgClass = firstArg.getClass();
        //更新操作
        if (value == OperationType.UPDATE) {
            //获取更新时间字段
            Field updateTime = firstArgClass.getDeclaredField("updateTime");
            //设置可访问
            updateTime.setAccessible(true);
            //设置更新时间
            updateTime.set(firstArg, LocalDateTime.now());
            //获取更新用户字段
            Field updateUser = firstArgClass.getDeclaredField("updateUser");
            //设置可访问
            updateUser.setAccessible(true);
            //设置更新用户
            updateUser.set(firstArg, currentId);
        } else if (value == OperationType.INSERT) {
            //获取创建时间字段
            Field createTime = firstArgClass.getDeclaredField("createTime");
            //设置可访问
            createTime.setAccessible(true);
            //设置创建时间
            createTime.set(firstArg, LocalDateTime.now());
            //获取创建用户字段
            Field createUser = firstArgClass.getDeclaredField("createUser");
            //设置可访问
            createUser.setAccessible(true);
            //设置创建用户
            createUser.set(firstArg, currentId);
            //获取更新时间字段
            Field updateTime = firstArgClass.getDeclaredField("updateTime");
            //设置可访问
            updateTime.setAccessible(true);
            //设置更新时间
            updateTime.set(firstArg, LocalDateTime.now());
            //获取更新用户字段
            Field updateUser = firstArgClass.getDeclaredField("updateUser");
            //设置可访问
            updateUser.setAccessible(true);

        }

    }


}
